#define ZCORE_SOURCE
#include "XMLNode.hpp"

#ifdef ZZZ_LIB_TINYXML
#define TIXML_USE_STL
#include <tinyxml/tinyxml.h>
#include <tinyxml/tinystr.h>
namespace zzz{

XMLNode::XMLNode(const XMLNode &node):node_(node.node_),root_(node.root_)
{}

XMLNode::XMLNode(TiXmlElement *node, const XML *root):node_(node),root_(root)
{}

//self
bool XMLNode::IsValid() const
{
  return node_!=NULL;
}

bool XMLNode::SetName(const string &name)
{
  node_->SetValue(name);
  return true;
}

//parent
XMLNode XMLNode::GetParent()
{
  ZCHECK(node_->Parent()!=NULL);
  return XMLNode(node_->Parent()->ToElement(),root_);
}

//children
zuint XMLNode::NodeNumber() const
{
  zuint x=0;
  for (const TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
    if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) x++;
  return x;
}

XMLNode XMLNode::GetNode(zuint i)
{
  zuint x=-1;
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) x++;
    if (x==i) return XMLNode(pChild->ToElement(),root_);
  }
  ZLOGF<<"Node "<<i<<" does not exist!";
  return XMLNode(NULL,root_);
}

XMLNode XMLNode::GetNode(const string &name)
{
  return GetFirstNode(name.c_str());
}

bool XMLNode::HasNode(const string &name)
{
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT && name == pChild->Value()) return true;
  }
  return false;
}

XMLNode XMLNode::AppendNode(const string &name)
{
  TiXmlElement *element=new TiXmlElement(name);
  node_->LinkEndChild(element);
  return XMLNode(element,root_);
}

bool XMLNode::RemoveNode(const string &name)
{
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (name == pChild->Value())
    {
      node_->RemoveChild(pChild);
      return true;
    }
  }
  return false;
}

bool XMLNode::RemoveNode(zuint i)
{
  zuint x=-1;
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) x++;
    if (x==i)
    {
      node_->RemoveChild(pChild);
      return true;
    }

  }
  return false;
}

//iteration
XMLNode XMLNode::GetFirstNode(const char *name)
{
  if (name==NULL)
  {
    for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) return XMLNode(pChild->ToElement(),root_);
    }
  }
  else
  {
    for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT && strcmp(name, pChild->Value())==0) 
        return XMLNode(pChild->ToElement(),root_);
    }
  }
  return XMLNode(NULL,root_);
}

XMLNode XMLNode::GetNextSibling(const char *name)
{
  if (name==NULL)
  {
    for (TiXmlNode *pChild=node_->NextSibling();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) return XMLNode(pChild->ToElement(),root_);
    }
  }
  else
  {
    for (TiXmlNode *pChild=node_->NextSibling();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT && strcmp(name,pChild->Value())==0)
        return XMLNode(pChild->ToElement(),root_);
    }
  }
  return XMLNode(NULL,root_);
}

void XMLNode::GotoNextSibling(const char *name)
{
  if (name==NULL)
  {
    for (TiXmlNode *pChild=node_->NextSibling();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT) 
      {
        node_=pChild->ToElement();
        return;
      }
    }
  }
  else
  {
    for (TiXmlNode *pChild=node_->NextSibling();pChild!=0;pChild=pChild->NextSibling())
    {
      if (pChild->Type()==TiXmlNode::TINYXML_ELEMENT && strcmp(name, pChild->Value())==0)
      {
        node_=pChild->ToElement();
        return;
      }
    }
  }
  node_=NULL;
  return;
}


void XMLNode::operator++()
{
  GotoNextSibling();
}

//attribute
bool XMLNode::HasAttribute(const string &name) const
{
  return node_->Attribute(name)!=NULL;
}

const char *XMLNode::GetAttribute(const string &name, const char *missing) const
{
  const string *res=node_->Attribute(name);
  return ((res!=NULL)?res->c_str():missing);
}

bool XMLNode::SetAttribute(const string &name, const char *value) const
{
  node_->SetAttribute(name,value);
  return true;
}

bool XMLNode::SetAttribute(const string &name, const string &value) const
{
  node_->SetAttribute(name,value.c_str());
  return true;
}

bool XMLNode::RemoveAttribute(const string &name)
{
  node_->RemoveAttribute(name);
  return true;
}

//Text
const char *XMLNode::GetText() const
{
  return node_->GetText();
}

bool XMLNode::SetText(const string &value) const
{
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (node_->Type()==TiXmlNode::TINYXML_TEXT)
    {
      pChild->SetValue(value);
      return true;
    }
  }
  node_->LinkEndChild(new TiXmlText(value));
  return true;
}

bool XMLNode::RemoveText()
{
  for (TiXmlNode *pChild=node_->FirstChild();pChild!=0;pChild=pChild->NextSibling())
  {
    if (node_->Type()==TiXmlNode::TINYXML_COMMENT)
    {
      node_->RemoveChild(pChild);
      return true;
    }
  }
  return true;
}

const char *XMLNode::GetName() const
{
  return node_->Value();
}
}
#endif // ZZZ_LIB_TINYXML
